# -*- coding: utf-8 -*-

import datetime

from django.db.models import Count
from django.conf import settings

from basic_info.models import Stock, Industry, StockIndustryMap, Concept, \
                                    StockConceptMap, Location, StockLocationMap
from companies.models import QA, QAStatisticsResult, StatisticsCategory, QuestionPolarity

class QAStatistics:
    
    def __init__(self, date, day_delta=1):
        self.date = date
        self.cycle = day_delta
        cur_datetime_min = date - datetime.timedelta(days=self.cycle)
        self.stats_by_stock = dict()
        self.stats_polarity_by_stock = dict()

        self.qa_set = QA.objects.filter(answer_date__gte=(cur_datetime_min))
        self.distinct_stocks = self.qa_set.values('stock').distinct()

    def get_qa_statistics(self):
        self.stats_by_stock = dict()
        self.stats_polarity_by_stock = dict()
        self.__get_qa_statistics_by_stock()
        self.__get_qa_statistics_by_industry()
        self.__get_qa_statistics_by_concept()
        self.__get_qa_statistics_by_location()
        self.__get_qa_statistics_by_question_category()

    def __get_qa_statistics_by_stock(self):
        
        stock_count_list = self.qa_set.values('stock').annotate(count=Count('stock'))

        for entry in self.distinct_stocks:
            stock = Stock.objects.get(pk=entry['stock'])
            self.__calcluate_qa_polarity_count(self.stats_polarity_by_stock, stock, self.qa_set)
                  
        for entry in stock_count_list:
            stock = entry['stock'] 
            stock_count = entry['count']

            self.stats_by_stock[stock] = stock_count
            stats_polarity_tuple  = self.stats_polarity_by_stock[stock]          

            QAStatisticsResult.objects.get_or_create(category=StatisticsCategory.COMPANY, 
                                                     name=stock,
                                                     date=self.date, 
                                                     cycle=self.cycle,
                                                     defaults={
                                                        'count': stock_count, 
                                                        'positive_count': stats_polarity_tuple[0],
                                                        'negative_count': stats_polarity_tuple[1],
                                                        'polarity_count': stats_polarity_tuple[2],
                                                        'positive_rate': stats_polarity_tuple[3],
                                                        'negative_rate': stats_polarity_tuple[4],
                                                     }) 
    
    def __get_qa_statistics_by_industry(self):
        self.__calculate_qa_question_count_by_category(Industry)
    
    def __get_qa_statistics_by_concept(self):
        self.__calculate_qa_question_count_by_category(Concept)
    
    def __get_qa_statistics_by_location(self):
        self.__calculate_qa_question_count_by_category(Location)

    def __calculate_qa_question_count_by_category(self, category_model):
    
        category_map = dict()

        for entry in self.distinct_stocks:
            stock = Stock.objects.get(pk=entry['stock'])
            categories = category_model.objects.filter(stocks__in=[stock])
            for category in categories:
                if category.name in category_map:
                    category_tuple = category_map[category.name]
                    count = category_tuple[0] + self.stats_by_stock[stock.code]
                    positive_count = category_tuple[1] + self.stats_polarity_by_stock[stock.code][0]
                    negative_count = category_tuple[2] + self.stats_polarity_by_stock[stock.code][1]
                    polarity_count = category_tuple[3] + self.stats_polarity_by_stock[stock.code][2]

                else:
                    count = self.stats_by_stock[stock.code]
                    positive_count = self.stats_polarity_by_stock[stock.code][0]
                    negative_count = self.stats_polarity_by_stock[stock.code][1]
                    polarity_count = self.stats_polarity_by_stock[stock.code][2]

                category_map[category.name] = (count, positive_count, negative_count, polarity_count, 0, 0)
        
        for category_name, category_tuple in category_map.iteritems():

            positive_rate, negative_rate = self.__calcluate_qa_polarity_rate(category_tuple[1], 
                                                                             category_tuple[2],
                                                                             category_tuple[3])
            QAStatisticsResult.objects.get_or_create(category=category_model.__name__, 
                                                     name=category_name, 
                                                     date=self.date, 
                                                     cycle=self.cycle,
                                                     defaults={
                                                        'count': category_tuple[0], 
                                                        'positive_count': category_tuple[1],
                                                        'negative_count': category_tuple[2],
                                                        'polarity_count': category_tuple[3],
                                                        'positive_rate': positive_rate,
                                                        'negative_rate': negative_rate,
                                                     })

    def __get_qa_statistics_by_question_category(self):
        # 统计不同类别中提问数量并排序
                
        sub_category_count_list = self.qa_set.values('sub_category').annotate(count=Count('sub_category'))

        for entry in sub_category_count_list:
            sub_category = entry['sub_category'] 
            sub_category_count = entry['count']

            QAStatisticsResult.objects.get_or_create(category=StatisticsCategory.QUESTION, 
                                                     name=sub_category,
                                                     date=self.date, 
                                                     cycle=self.cycle,
                                                     defaults={
                                                        'count': sub_category_count,
                                                     }) 

    def __calculate_qa_question_count(self, stats_by_category, stock, category_name, qa_set):
        question_count = qa_set.objects.filter(
                                        stock=stock, 
                                        ).count()
        if stats_by_category.has_key(category_name):
            stats_by_category[category_name] += question_count
        else:
            stats_by_category[category_name] = question_count
    
    def __calcluate_qa_polarity_count(self, stats_polarity_by_stock, stock, qa_set):
        positive_count = qa_set.filter(stock=stock, 
                                       polarity = QuestionPolarity.POSITIVE).count()
        negative_count = qa_set.filter(stock=stock, 
                                       polarity = QuestionPolarity.NEGATIVE).count()
        polarity_count = positive_count + negative_count
    
        positive_rate, negative_rate = self.__calcluate_qa_polarity_rate(positive_count, 
                                                                         negative_count, 
                                                                         polarity_count)

        stats_polarity_by_stock[stock.code] = (positive_count,
                                          negative_count,
                                          polarity_count,
                                          positive_rate, 
                                          negative_rate)
    
    def __calcluate_qa_polarity_rate(self, positive_count, negative_count, polarity_count):
        if polarity_count == 0:
            positive_rate = 0
            negative_rate = 0
        else:
            positive_rate = float(positive_count) / polarity_count
            negative_rate = float(negative_count) / polarity_count

        return positive_rate, negative_rate
